package com.baidu.iit.pvm.runtime;

import com.baidu.iit.pvm.*;
import com.baidu.iit.pvm.delegate.ActivityExecution;
import com.baidu.iit.pvm.delegate.ExecutionListenerExecution;
import com.baidu.iit.pvm.delegate.SignallableActivityBehavior;
import com.baidu.iit.pvm.process.ActivityImpl;
import com.baidu.iit.pvm.process.ProcessDefinitionImpl;
import com.baidu.iit.pvm.process.TransitionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.*;

/**
 * 执行器的具体实现类，由这个类的实例控制流程怎么调度
 * Created by 卫立 on 2014/4/7.
 *
 * @NotThreadSafe
 */
public class ExecutionImpl implements
        Serializable,
        ActivityExecution,
        ExecutionListenerExecution,
        PvmExecution,
        InterpretableExecution {

    private static Logger log = LoggerFactory.getLogger(ExecutionImpl.class);

    // 流程定义
    protected ProcessDefinitionImpl processDefinition;

    //开始节点
    protected ActivityImpl activity;

    //路径
    protected TransitionImpl transition = null;

    //流程实例
    protected ExecutionImpl processInstance;

    //上级流程执行器
    protected ExecutionImpl parent;

    //流程执行器
    protected List<ExecutionImpl> executions;

    //下级执行器
    protected ExecutionImpl superExecution;

    //子流程实例
    protected ExecutionImpl subProcessInstance;


    //开始流程器
    protected StartingExecution startingExecution;


    protected boolean isActive = true;
    protected boolean isScope = true;
    protected boolean isConcurrent = false;
    protected boolean isEnded = false;
    protected boolean isEventScope = false;

    //上下问参数
    protected Map<String, Object> variables = null;

    //事件名称
    protected String eventName;
    //事件的源头
    protected PvmProcessElement eventSource;
    //事件执行顺序
    protected int executionListenerIndex = 0;


    //删除起始单元
    protected boolean deleteRoot;
    //删除原因
    protected String deleteReason;

    //需要替换换的执行器
    protected ExecutionImpl replacedBy;


    //下一个执行操作
    protected AtomicOperation nextOperation;

    //是否正在执行操作
    protected boolean isOperating = false;

    public ExecutionImpl() {
    }

    public ExecutionImpl(ActivityImpl initial) {
        startingExecution = new StartingExecution(initial);
    }


    //创建执行对象
    public ExecutionImpl createExecution() {
        ExecutionImpl createdExecution = newExecution();

        ensureExecutionsInitialized();
        executions.add(createdExecution);
        createdExecution.setParent(this);

        createdExecution.setProcessDefinition(getProcessDefinition());
        createdExecution.setProcessInstance(getProcessInstance());
        createdExecution.setActivity(getActivity());

        return createdExecution;
    }

    //创建新的对象实例，该类不能对外提供功能开放，否则可能导致循环对象的产生
    protected ExecutionImpl newExecution() {
        return new ExecutionImpl();
    }


    //创建子流程
    public PvmProcessInstance createSubProcessInstance(PvmProcessDefinition processDefinition) {
        ExecutionImpl subProcessInstance = newExecution();

        subProcessInstance.setSuperExecution(this);
        this.setSubProcessInstance(subProcessInstance);

        subProcessInstance.setProcessDefinition((ProcessDefinitionImpl) processDefinition);
        subProcessInstance.setProcessInstance(subProcessInstance);

        return subProcessInstance;
    }


    public void initialize() {
        //TODO 初始化SCOPE相关的内容，暂时无用
    }


    //标准节点不是单元节点，删除形成的流程单元
    public void destroy() {
        setScope(false);
    }

    //从执行队列里移除当前对象
    public void remove() {
        if (parent != null) {
            parent.ensureExecutionsInitialized();
            parent.executions.remove(this);
        }

        List<InterpretableExecution> childExecutions = new ArrayList<InterpretableExecution>(getExecutions());
        for (InterpretableExecution childExecution : childExecutions) {
            if (childExecution.isEventScope()) {
                log.debug("removing eventScope {}", childExecution);
                childExecution.destroy();
                childExecution.remove();
            }
        }
    }

    /**
     * 递归删除执行单元
     *
     * @param reason
     */
    public void destroyScope(String reason) {

        if (log.isDebugEnabled()) {
            log.debug("performing destroy scope behavior for execution {}", this);
        }

        List<InterpretableExecution> executions = new ArrayList<InterpretableExecution>(getExecutions());
        for (InterpretableExecution childExecution : executions) {
            if (childExecution.getSubProcessInstance() != null) {
                childExecution.getSubProcessInstance().deleteCascade(reason);
            }
            childExecution.deleteCascade(reason);
        }

    }

    /**
     * 获取上级对象
     *
     * @return
     */
    public ExecutionImpl getParent() {
        return parent;
    }

    /**
     * 获取上级对象的ID
     *
     * @return
     */
    public String getParentId() {
        if (parent != null) {
            return parent.getId();
        }
        return null;
    }

    /**
     * 设置上级对象
     *
     * @param parent
     */
    public void setParent(InterpretableExecution parent) {
        this.parent = (ExecutionImpl) parent;
    }



    public List<ExecutionImpl> getExecutions() {
        ensureExecutionsInitialized();
        return executions;
    }

    public ExecutionImpl getSuperExecution() {
        ensureSuperExecutionInitialized();
        return superExecution;
    }

    public void setSuperExecution(ExecutionImpl superExecution) {
        this.superExecution = superExecution;
        if (superExecution != null) {
            superExecution.setSubProcessInstance(null);
        }
    }

    protected void ensureSuperExecutionInitialized() {
    }

    public ExecutionImpl getSubProcessInstance() {
        ensureSubProcessInstanceInitialized();
        return subProcessInstance;
    }

    public void setSubProcessInstance(InterpretableExecution subProcessInstance) {
        this.subProcessInstance = (ExecutionImpl) subProcessInstance;
    }

    protected void ensureSubProcessInstanceInitialized() {
    }

    /**
     * 删除相关的节点
     *
     * @param deleteReason
     */
    public void deleteCascade(String deleteReason) {
        this.deleteReason = deleteReason;
        this.deleteRoot = true;
        performOperation(AtomicOperation.DELETE_CASCADE);
    }


    //结束当前的流程
    public void end() {
        isActive = false;
        isEnded = true;
        performOperation(AtomicOperation.ACTIVITY_END);
    }

    //根据对应的节点ID查找对应的执行对象
    public ExecutionImpl findExecution(String activityId) {
        //当当前的对象Id相等的时候翻回当前
        if ((getActivity() != null)
                && (getActivity().getId().equals(activityId))
                ) {
            return this;
        }


        for (ExecutionImpl nestedExecution : getExecutions()) {
            ExecutionImpl result = nestedExecution.findExecution(activityId);
            if (result != null) {
                return result;
            }
        }
        return null;
    }


    //获取所有的执行单元活及活动节点
    public List<String> findActiveActivityIds() {
        List<String> activeActivityIds = new ArrayList<String>();
        collectActiveActivityIds(activeActivityIds);
        return activeActivityIds;
    }


    //从执行器中提取所有相关的节点
    protected void collectActiveActivityIds(List<String> activeActivityIds) {
        if (isActive && activity != null) {
            activeActivityIds.add(activity.getId());
        }
        ensureExecutionsInitialized();
        for (ExecutionImpl execution : executions) {
            execution.collectActiveActivityIds(activeActivityIds);
        }
    }

    /**
     * 确保executions变量已经初始化
     */
    protected void ensureExecutionsInitialized() {
        if (executions == null) {
            executions = new ArrayList<ExecutionImpl>();
        }
    }

    /**
     * 获取流程定义
     *
     * @return
     */
    public ProcessDefinitionImpl getProcessDefinition() {
        return processDefinition;
    }


    /**
     * 获取流程定义的ID
     *
     * @return
     */
    public String getProcessDefinitionId() {
        return getProcessDefinition().getId();
    }


    /**
     * 获取流程实例
     *
     * @return
     */
    public ExecutionImpl getProcessInstance() {
        return processInstance;
    }

    public String getProcessInstanceId() {
        return getProcessInstance().getId();
    }


    public void setProcessInstance(InterpretableExecution processInstance) {
        this.processInstance = (ExecutionImpl) processInstance;
    }

    /**
     * 获取当前的流程节点
     *
     * @return
     */
    public ActivityImpl getActivity() {
        return activity;
    }


    public void setActivity(ActivityImpl activity) {
        this.activity = activity;
    }


    public boolean isScope() {
        return isScope;
    }

    public void setScope(boolean isScope) {
        this.isScope = isScope;
    }


    /**
     * 流程实例开始流转的入口
     */
    public void start() {
        if (startingExecution == null && isProcessInstanceType()) {
            startingExecution = new StartingExecution(processDefinition.getInitial());
        }
        performOperation(AtomicOperation.PROCESS_START);
    }

    /**
     * 中断流程的继续 触发操作
     *
     * @param signalName 触发的 跳转名称
     * @param signalData 传递的参数
     */
    public void signal(String signalName, Object signalData) {

        SignallableActivityBehavior activityBehavior = (SignallableActivityBehavior) activity.getActivityBehavior();

        try {
            activityBehavior.signal(this, signalName, signalData);
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new PvmException("触发后续操作 '" + signalName + "' 在节点 '" + activity.getId() + "': " + e.getMessage(), e);
        }
    }


    /**
     * 选择要跳转的后续路径
     *
     * @param transition
     */
    public void take(PvmTransition transition) {
        if (this.transition != null) {
            throw new PvmException("已经存在跳转路径了!");
        }
        if (transition == null) {
            throw new PvmException("跳转的路径不能为空!");
        }
        setTransition((TransitionImpl) transition);
        //触发路径跳转完毕事件
        performOperation(AtomicOperation.TRANSITION_NOTIFY_LISTENER_END);
    }


    /**
     * 执行当前节点的动作
     *
     * @param activity
     */
    public void executeActivity(PvmActivity activity) {
        setActivity((ActivityImpl) activity);
        //触发流程节点的开始事件
        performOperation(AtomicOperation.ACTIVITY_START);
    }


    /**
     * 根据节点获取所有为执行的操作
     *
     * @param activity
     * @return
     */
    public List<ActivityExecution> findInactiveConcurrentExecutions(PvmActivity activity) {
        List<ActivityExecution> inactiveConcurrentExecutionsInActivity = new ArrayList<ActivityExecution>();
        List<ActivityExecution> otherConcurrentExecutions = new ArrayList<ActivityExecution>();
        if (isConcurrent()) {
            List<? extends ActivityExecution> concurrentExecutions = getParent().getExecutions();
            for (ActivityExecution concurrentExecution : concurrentExecutions) {
                if (concurrentExecution.getActivity() == activity) {
                    if (concurrentExecution.isActive()) {
                        throw new PvmException("didn't expect active execution in " + activity + ". bug?");
                    }
                    inactiveConcurrentExecutionsInActivity.add(concurrentExecution);
                } else {
                    otherConcurrentExecutions.add(concurrentExecution);
                }
            }
        } else {
            if (!isActive()) {
                inactiveConcurrentExecutionsInActivity.add(this);
            } else {
                otherConcurrentExecutions.add(this);
            }
        }

        return inactiveConcurrentExecutionsInActivity;
    }


    /**
     * 执行所有的后续路径
     *
     * @param transitions
     * @param recyclableExecutions
     */
    public void takeAll(List<PvmTransition> transitions, List<ActivityExecution> recyclableExecutions) {
        transitions = new ArrayList<PvmTransition>(transitions);
        recyclableExecutions = (recyclableExecutions != null ? new ArrayList<ActivityExecution>(recyclableExecutions) : new ArrayList<ActivityExecution>());

        if (recyclableExecutions.size() > 1) {
            for (ActivityExecution recyclableExecution : recyclableExecutions) {
                if (((ExecutionImpl) recyclableExecution).isScope()) {
                    throw new PvmException("不允许执行join操作");
                }
            }
        }

        ExecutionImpl concurrentRoot = ((isConcurrent && !isScope) ? getParent() : this);

        List<ExecutionImpl> concurrentActiveExecutions = new ArrayList<ExecutionImpl>();
        for (ExecutionImpl execution : concurrentRoot.getExecutions()) {
            if (execution.isActive()) {
                concurrentActiveExecutions.add(execution);
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("transitions to take concurrent: {}", transitions);
            log.debug("active concurrent executions: {}", concurrentActiveExecutions);
        }

        if ((transitions.size() == 1) && (concurrentActiveExecutions.isEmpty())) {

            List<ExecutionImpl> recyclableExecutionImpls = (List) recyclableExecutions;
            for (ExecutionImpl prunedExecution : recyclableExecutionImpls) {
                if (!prunedExecution.isEnded()) {
                    prunedExecution.remove();
                }
            }

            concurrentRoot.setActive(true);
            concurrentRoot.setActivity(activity);
            concurrentRoot.setConcurrent(false);
            concurrentRoot.take(transitions.get(0));

        } else {

            List<OutgoingExecution> outgoingExecutions = new ArrayList<OutgoingExecution>();

            recyclableExecutions.remove(concurrentRoot);
            while (!transitions.isEmpty()) {
                PvmTransition outgoingTransition = transitions.remove(0);

                ExecutionImpl outgoingExecution = null;
                if (recyclableExecutions.isEmpty()) {
                    outgoingExecution = concurrentRoot.createExecution();
                } else {
                    outgoingExecution = (ExecutionImpl) recyclableExecutions.remove(0);
                }

                outgoingExecution.setActive(true);
                outgoingExecution.setScope(false);
                outgoingExecution.setConcurrent(true);
                outgoingExecutions.add(new OutgoingExecution(outgoingExecution, outgoingTransition, true));
            }


            for (ActivityExecution prunedExecution : recyclableExecutions) {
                prunedExecution.end();
            }

            for (OutgoingExecution outgoingExecution : outgoingExecutions) {
                outgoingExecution.take();
            }
        }
    }

    /**
     * 执行调度的触发函数
     * @param executionOperation
     */
    public void performOperation(AtomicOperation executionOperation) {
        this.nextOperation = executionOperation;
        if (!isOperating) {
            isOperating = true;
            while (this.nextOperation != null) {
                AtomicOperation currentOperation = this.nextOperation;
                this.nextOperation = null;
                if (log.isDebugEnabled()) {
                    log.debug("AtomicOperation: {} on {}", currentOperation, this);
                }
                currentOperation.execute(this);
            }
            isOperating = false;
        }
    }


    /**
     * 判断节点是否是可用的
     * @param activityId
     * @return
     */
    public boolean isActive(String activityId) {
        return findExecution(activityId) != null;
    }


    /**
     * 获取上下文变量
     * @param variableName 变量名称
     * @return
     */
    public Object getVariable(String variableName) {
        ensureVariablesInitialized();

        if (variables.containsKey(variableName)) {
            return variables.get(variableName);
        }
        //当在当前的执行的上下文中找不到变量时尝试往上级节点找
        if (parent != null) {
            return parent.getVariable(variableName);
        }

        return null;
    }

    /**
     * 获取所有的上下文变量
     * @return
     */
    public Map<String, Object> getVariables() {
        Map<String, Object> collectedVariables = new HashMap<String, Object>();
        collectVariables(collectedVariables);
        return collectedVariables;
    }


    /**
     * 上下问变量搜集
     * @param collectedVariables
     */
    protected void collectVariables(Map<String, Object> collectedVariables) {
        if (parent != null) {
            parent.collectVariables(collectedVariables);
        }
        ensureVariablesInitialized();
        for (String variableName : variables.keySet()) {
            collectedVariables.put(variableName, variables.get(variableName));
        }
    }

    /**
     * 设置全局的上下文的变量
     * @param variables
     */
    public void setVariables(Map<String, ? extends Object> variables) {
        ensureVariablesInitialized();
        if (variables != null) {
            for (String variableName : variables.keySet()) {
                setVariable(variableName, variables.get(variableName));
            }
        }
    }

    public void setVariable(String variableName, Object value) {
        ensureVariablesInitialized();
        if (variables.containsKey(variableName)) {
            setVariableLocally(variableName, value);
        } else {
            if (parent != null) {
                parent.setVariable(variableName, value);
            } else {
                setVariableLocally(variableName, value);
            }
        }
    }

    /**
     * 设置当前变量
     * @param variableName
     * @param value
     */
    public void setVariableLocally(String variableName, Object value) {
        variables.put(variableName, value);
    }


    /**
     * 判断某个变量是否存在
     * @param variableName
     * @return
     */
    public boolean hasVariable(String variableName) {
        ensureVariablesInitialized();
        if (variables.containsKey(variableName)) {
            return true;
        }
        if (parent != null) {
            return parent.hasVariable(variableName);
        }
        return false;
    }

    protected void ensureVariablesInitialized() {
        if (variables == null) {
            variables = new HashMap<String, Object>();
        }
    }


    public String toString() {
        if (isProcessInstanceType()) {
            return "ProcessInstance[" + getToStringIdentity() + "]";
        } else {
            return (isEventScope ? "EventScope" : "") + (isConcurrent ? "Concurrent" : "") + (isScope() ? "Scope" : "") + "Execution[" + getToStringIdentity() + "]";
        }
    }

    protected String getToStringIdentity() {
        return Integer.toString(System.identityHashCode(this));
    }


    /**
     * 判断当前对象是否是流程实例
     * @return
     */
    public boolean isProcessInstanceType() {
        return parent == null;
    }


    public void inactivate() {
        this.isActive = false;
    }

    public String getId() {
        return null;
    }


    /**
     * 获取当前的跳转路径
     * @return
     */
    public TransitionImpl getTransition() {
        return transition;
    }

    public void setTransition(TransitionImpl transition) {
        this.transition = transition;
    }

    /**
     * 获取当前监控器的执行点
     * @return
     */
    public Integer getExecutionListenerIndex() {
        return executionListenerIndex;
    }


    /**
     * 设置执行那个监控
     * @param executionListenerIndex
     */
    public void setExecutionListenerIndex(Integer executionListenerIndex) {
        this.executionListenerIndex = executionListenerIndex;
    }


    /**
     * 是否是并发执行
     * @return
     */
    public boolean isConcurrent() {
        return isConcurrent;
    }

    public void setConcurrent(boolean isConcurrent) {
        this.isConcurrent = isConcurrent;
    }

    /**
     * 是否是有效的
     * @return
     */
    public boolean isActive() {
        return isActive;
    }

    public void setActive(boolean isActive) {
        this.isActive = isActive;
    }

    public boolean isEnded() {
        return isEnded;
    }

    public void setProcessDefinition(ProcessDefinitionImpl processDefinition) {
        this.processDefinition = processDefinition;
    }

    public String getEventName() {
        return eventName;
    }

    public void setEventName(String eventName) {
        this.eventName = eventName;
    }

    public PvmProcessElement getEventSource() {
        return eventSource;
    }

    public void setEventSource(PvmProcessElement eventSource) {
        this.eventSource = eventSource;
    }

    public String getDeleteReason() {
        return deleteReason;
    }

    public void setDeleteReason(String deleteReason) {
        this.deleteReason = deleteReason;
    }

    public ExecutionImpl getReplacedBy() {
        return replacedBy;
    }

    public void setReplacedBy(InterpretableExecution replacedBy) {
        this.replacedBy = (ExecutionImpl) replacedBy;
    }

    public void setExecutions(List<ExecutionImpl> executions) {
        this.executions = executions;
    }

    public boolean isDeleteRoot() {
        return deleteRoot;
    }

    public String getCurrentActivityId() {
        String currentActivityId = null;
        if (this.activity != null) {
            currentActivityId = activity.getId();
        }
        return currentActivityId;
    }

    public String getCurrentActivityName() {
        String currentActivityName = null;
        if (this.activity != null) {
            currentActivityName = (String) activity.getProperty("name");
        }
        return currentActivityName;
    }


    public void createVariableLocal(String variableName, Object value) {

    }

    public void createVariablesLocal(Map<String, ? extends Object> variables) {

    }


    public Object getVariableLocal(String variableName) {
        return null;
    }

    public Set<String> getVariableNames() {
        return null;
    }

    public Set<String> getVariableNamesLocal() {
        return null;
    }

    public Map<String, Object> getVariablesLocal() {
        return null;
    }

    public boolean hasVariableLocal(String variableName) {
        return false;
    }

    public boolean hasVariables() {
        return false;
    }

    public boolean hasVariablesLocal() {
        return false;
    }

    public void removeVariable(String variableName) {
    }

    public void removeVariableLocal(String variableName) {
    }

    public void removeVariables(Collection<String> variableNames) {
    }

    public void removeVariablesLocal(Collection<String> variableNames) {
    }

    public void removeVariables() {
    }

    public void removeVariablesLocal() {
    }

    public void deleteVariablesLocal() {

    }

    public Object setVariableLocal(String variableName, Object value) {
        return null;
    }

    public void setVariablesLocal(Map<String, ? extends Object> variables) {
    }

    public boolean isEventScope() {
        return isEventScope;
    }

    public void setEventScope(boolean isEventScope) {
        this.isEventScope = isEventScope;
    }

    public StartingExecution getStartingExecution() {
        return startingExecution;
    }

    public void disposeStartingExecution() {
        startingExecution = null;
    }

}
